package cn.tpshion.devops.node;

import cn.tpshion.devops.common.constant.RedisKey;
import cn.tpshion.devops.common.enums.MsgType;
import cn.tpshion.devops.common.enums.NodeType;
import cn.tpshion.devops.common.constant.NodeConstant;
import cn.tpshion.devops.domain.entity.GitSecretData;
import cn.tpshion.devops.domain.entity.MsgData;
import cn.tpshion.devops.domain.entity.NodeData;
import cn.tpshion.devops.domain.entity.SecretData;
import cn.tpshion.devops.node.data.GitData;
import cn.tpshion.devops.node.support.MsgProgressMonitor;
import cn.tpshion.devops.node.support.NodeContext;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * git节点
 */
@Slf4j
@Component
public class GitNode extends Node<GitData> {

    @Value("${node.workspace}")
    private String workspace;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public NodeType nodeType() {
        return NodeType.GIT;
    }

    @Override
    public void handle(NodeContext nodeContext) throws Exception {
        log.info("GitNode nodeContext:{}", nodeContext);
        sseHandle.sendMessage(nodeContext, new MsgData(MsgType.INFO, "开始执行git节点"));

        GitData data = getData(nodeContext);
        log.info("GitNode data:{}", data);

        UsernamePasswordCredentialsProvider credentials = new UsernamePasswordCredentialsProvider(data.getUsername(), data.getPassword());

        String uri = data.getUrl();
        String name = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));
        String branch = StringUtils.hasText(data.getBranch()) ? data.getBranch() : data.getDefaultBranch();

        sseHandle.sendMessage(nodeContext, new MsgData(MsgType.INFO, "项目地址：" + data.getUrl()));
        sseHandle.sendMessage(nodeContext, new MsgData(MsgType.INFO, "执行git分支：" + branch));

        File file = new File(workspace + File.separator + nodeContext.getTaskId() + File.separator + name);
        String commitVersion = null;
        String commitMsg = null;
        if(file.exists() && file.isDirectory()){

            try (Git git = new Git(new FileRepository(file.getPath() + "/.git"))) {
                ListBranchCommand branchList = git.branchList();
                List<Ref> refList = branchList.call();
                boolean createBranch = true;
                for (Ref ref : refList) {
                    log.info("getBranchList branch:{} name:{}", ref.getName(), ref.getObjectId().getName());
                    if(StringUtils.startsWithIgnoreCase(ref.getName(), "refs/heads/" + branch)){
                        createBranch = false;
                        break;
                    }
                }

                git.checkout()
                        .setName(branch)
                        .setProgressMonitor(new MsgProgressMonitor(nodeContext, sseHandle))
                        .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM)
                        .setStartPoint("origin/" + branch)
                        .setForced(true)
                        .setCreateBranch(createBranch)
                        .call();

                git.pull()
                        .setProgressMonitor(new MsgProgressMonitor(nodeContext, sseHandle))
                        .setCredentialsProvider(credentials)
                        .call();

                log.info("仓库地址:{}", git.getRepository().getDirectory());
                MsgData msgData = new MsgData(MsgType.INFO, "仓库地址：" + git.getRepository().getDirectory());
                sseHandle.sendMessage(nodeContext, msgData);

                Iterable<RevCommit> commits = git.log().call();
                for (RevCommit commit : commits) {
                    log.info("commitVersion:{} commitMsg:{}", commit.getName(), commit.getShortMessage());
                    commitVersion = commit.getName();
                    commitMsg = commit.getShortMessage();

                    MsgData commitMsgData = new MsgData(MsgType.INFO, "提交版本号：" + commit.getName() + " 提交信息：" + commit.getShortMessage());
                    sseHandle.sendMessage(nodeContext, commitMsgData);
                    break;
                }
            }
        }else{
            FileUtils.deleteDirectory(file);
            try (Git git = Git.cloneRepository()
                    .setURI(data.getUrl())
                    .setBranch(branch)
                    .setDirectory(file)
                    .setCredentialsProvider(credentials)
                    .call()) {

                log.info("仓库地址:{}", git.getRepository().getDirectory());

                MsgData msgData = new MsgData(MsgType.INFO, "仓库地址：" + git.getRepository().getDirectory());
                sseHandle.sendMessage(nodeContext, msgData);

                Iterable<RevCommit> commits = git.log().call();
                for (RevCommit commit : commits) {
                    log.info("commitVersion:{} commitMsg:{}", commit.getName(), commit.getShortMessage());
                    commitVersion = commit.getName();
                    commitMsg = commit.getShortMessage();

                    MsgData commitMsgData = new MsgData(MsgType.INFO, "提交版本号：" + commit.getName() + " 提交信息：" + commit.getShortMessage());
                    sseHandle.sendMessage(nodeContext, commitMsgData);
                    break;
                }
            }
        }

        Map<String, Object> contextData = nodeContext.getData();
        contextData.put(NodeConstant.WORKSPACE, file.getPath());
        contextData.put(NodeConstant.GIT_BRANCH, branch);
        contextData.put(NodeConstant.GIT_COMMIT_VERSION, commitVersion);
        contextData.put(NodeConstant.GIT_COMMIT_MSG, commitMsg);
    }

    @Override
    protected GitData getData(NodeContext nodeContext) {
        NodeData nodeData = nodeContext.getNodeData();
        GitData data = JSON.parseObject(JSON.toJSONString(nodeData.getData()), GitData.class);

        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String value = hash.get(RedisKey.SECRET, data.getSecretName());
        SecretData secretData = JSON.parseObject(value, SecretData.class);
        GitSecretData gitSecretData = JSON.parseObject(JSON.toJSONString(secretData.getData()), GitSecretData.class);

        data.setUsername(gitSecretData.getUsername());
        data.setPassword(gitSecretData.getPassword());
        return data;
    }

}
